﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Interface;
using System.Threading;
using System.Collections;
using LogicAnalyzerCommon;
using System.Diagnostics;

namespace SimpleLogicAnalyzer
{
    public class VirtualSlaCommunication : ICommunication
    {
        private uint _baudrate;
        private IList<byte> _answer;

        public int ReadTimeout { get; set; }
        public int BytesToRead { get { return _answer.Count; } }

        public VirtualSlaCommunication(uint baudrate)
        {
            _baudrate = baudrate;
            _answer = new List<byte>();
        }

        public int ReadByte()
        {
            // Use baudrate to simulate transmission time
            Thread.Sleep((int)(((1.0 / _baudrate) * 10.0/*bits*/) * 1000.0/*ms*/));

            if (_answer.Count == 0)
            {
                Thread.Sleep(ReadTimeout);
                if (_answer.Count == 0)
                {
                    throw new TimeoutException();
                }
            }
            byte b = (byte)_answer[0];
            _answer.RemoveAt(0);
            return b;
        }

        public int ReadChar()
        {
            return ReadByte();
        }

        private void HandleCommand(string command)
        {
            // Wake up
            if (command == "I")
            {
                foreach(char c in "SLA_ANTONIAK_V1")
                {
                    _answer.Add((byte)c);
                }
            }
            // Reset
            if (command == "Q")
            {
                if(_answer.Count > 0)
                {
                    _answer.Clear();
                }
            }
            // Acquire
            if (command[0] == 'A' && command.Length == 7)
            {
                //SimpleLogicAnalyzerSettings simpleLogicAnalyzerSettings = SimpleLogicAnalyzerSettings.CreateFromDeviceData(command);

                byte autoCompareTriggerLevel = (byte)command[3];
                int sampleSize = 0;
                switch((byte)command[5] - 1)
                {
                    case 0: sampleSize = 1024; break;
                    case 1: sampleSize = 2048; break;
                    case 2: sampleSize = 4096; break;
                    case 3: sampleSize = 8192; break;
                    case 4: sampleSize = 16384; break;
                    case 5: sampleSize = 32768; break;
                }
                byte startValue = autoCompareTriggerLevel;
                for (int i = 0; i < sampleSize; i++)
                {
                    _answer.Add(startValue++);
                }
                // Add the CRC
                _answer.Add(_answer.Crc8Dallas());
            }
        }

        public void Write(string text)
        {
            HandleCommand(text);

            Console.WriteLine("Write: '{0}'", text);
        }

        public void Write(byte[] buffer, int offset, int count)
        {
            StringBuilder stringBuilder = new StringBuilder(buffer.Length);

            for (int index = offset; index < count; index++ )
            {
                stringBuilder.Append((char)buffer[index]);
            }
            HandleCommand(stringBuilder.ToString());

            Console.WriteLine("Write: '{0}'", buffer);
        }

        public void Write(char[] buffer, int offset, int count)
        {
            StringBuilder stringBuilder = new StringBuilder(buffer.Length);
            for (int index = offset; index < count; index++)
            {
                stringBuilder.Append(buffer[index]);
            }
            HandleCommand(stringBuilder.ToString());

            Console.WriteLine("Write: '{0}'", buffer);
        }

        public void Open()
        {
            Console.WriteLine("Open");
        }

        public void Close()
        {
            Console.WriteLine("Close");
        }

        public void Dispose()
        {
            Console.WriteLine("Dispose");
        }

        public string[] PortNames
        {
            get { return new string[] {"Simple Logic Analyzer Emulator"}; }
        }

        public string PortName
        {
            get
            {
                throw new NotImplementedException();
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        public int Read(byte[] buffer, int offset, int count)
        {
            Debug.Assert(offset == 0);
            Debug.Assert(count >= 1);
            buffer[0] = (byte)ReadByte();
            return 1;
        }
    }
}
